package com.deng.framework.beans.factory.support;

import com.deng.framework.beans.BeansException;
import com.deng.framework.beans.factory.FactoryBean;
import com.deng.framework.beans.factory.config.BeanDefinition;
import com.deng.framework.beans.factory.config.BeanPostProcessor;
import com.deng.framework.beans.factory.config.ConfigurableBeanFactory;
import com.deng.framework.core.convert.ConversionService;
import com.deng.framework.utils.ClassUtils;
import com.deng.framework.utils.StringValueResolver;

import java.util.ArrayList;
import java.util.List;

/**
 * 获取Bean实例的工厂
 * tips:这里原来是implements BeanFactory，后来改成了implements ConfigurableBeanFactory。原因是要进行Bean的自定义扩展
 * ConfigurableBeanFactory相比于原来的BeanFactory多了一个Bean的扩展功能，所以这里作了进一步的修改
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    /**
     * 对BeanFactory方法的实现
     */
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null);
    }

    @Override
    public Object getBean(String name, Object... args) throws org.springframework.beans.BeansException {
        return doGetBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) getBean(name);
    }

    @Override
    public boolean containsBean(String name) {
        return containsBeanDefinition(name);
    }

    protected abstract boolean containsBeanDefinition(String beanName);

    // 使用泛型来定义一个获取Bean的方法,这里感觉直接使用Object也可以，反正泛型的原理也是Object+类型强转
    protected <T> T doGetBean(final String name, final Object[] args){
        //首先会先去三级缓存中获取,判断在不在map中，如果有实例化就直接返回实例化的bean
        Object sharedInstance = getSingleton(name);
        if (sharedInstance != null) {
            return (T) getObjectForBeanInstance(sharedInstance, name);
        }
        //没有的话就创建对应的Bean实例化
        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition, args);
        return (T) getObjectForBeanInstance(bean, name);
    }

    private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        //如果不是FactoryBean则直接返回
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }
        // 如果是 FactoryBean，则需要调用 FactoryBean的getObject
        Object object = getCachedObjectForFactoryBean(beanName);

        if (object == null) {
            FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
            object = getObjectFromFactoryBean(factoryBean, beanName);
        }

        return object;
    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;

    /**
     * 对ConfigurableBeanFactory类的扩展
     */
    //BeanPostProcessors to apply in createBean
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

    //实现ConfigurableBeanFactory中的addBeanPostProcessor方法
    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

    //beanPostProcessors of get
    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    /**
     *  获取ClassLoader的补充
     */
    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

    /**
     * 注解处理部分
     */
    //String resolvers to apply e.g. to annotation attribute values
    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();

    @Override
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        this.embeddedValueResolvers.add(valueResolver);
    }

    @Override
    public String resolveEmbeddedValue(String value) {
        String result = value;
        for (StringValueResolver resolver : this.embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result;
    }

    /**
     * spring数据转换FactoryBean部分
     */
    private ConversionService conversionService;
    @Override
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Override
    public ConversionService getConversionService() {
        return conversionService;
    }
}
